/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.ext.kdez;

import org.zkoss.lang.Objects;
import org.zkoss.lang.Strings;
import org.zkoss.zk.au.out.AuFocus;
import org.zkoss.zk.ui.AbstractComponent;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.InputEvent;
import org.zkoss.zk.ui.ext.Disable;
import org.zkoss.zk.ui.ext.Readonly;

import cn.easyplatform.web.ext.Assignable;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class Kindeditor extends AbstractComponent implements Disable,
		Assignable, Readonly {

	/**
	 * 
	 */
	private static final long serialVersionUID = 3560120584971251422L;

	private String _value = "";

	private String _width;

	private String _height;

	private String _toolbar;

	private String _txtByClient;

	private String _hflex;

	private String _vflex;

	private String _skin;

	private String _noDisableItems;

	private String _items;

	private String _langType;

	private String _urlType;

	private String _newlineTag;

	private boolean _autoHeight;

	private boolean _disabled;

	private boolean _filterMode;

	private boolean _wellFormatMode = true;

	private boolean _designMode = true;

	private boolean _fullscreenMode;

	private boolean _useContextmenu = true;

	private boolean _allowPreviewEmoticons;

	private boolean _allowImageUpload;

	private boolean _allowFlashUpload;

	private boolean _allowMediaUpload;

	private boolean _allowFileUpload;

	private boolean _allowFileManager;

	private boolean _fullscreenShortcut;

	private boolean _fillDescAfterUploadImage;

	private boolean _allowImageRemote;

	// 2或1或0，2时可以拖动改变宽度和高度，1时只能改变高度，0时不能拖动。
	private int _resizeType;

	private int _minWidth;

	private int _minHeight;

	private String _ctrlKey;

	static {
		addClientEvent(Kindeditor.class, Events.ON_CHANGE, CE_IMPORTANT
				| CE_REPEAT_IGNORE | CE_NON_DEFERRABLE);
		addClientEvent(Kindeditor.class, Events.ON_CHANGING, CE_BUSY_IGNORE
				| CE_NON_DEFERRABLE);
		addClientEvent(Kindeditor.class, Events.ON_CTRL_KEY, CE_IMPORTANT
				| CE_REPEAT_IGNORE | CE_NON_DEFERRABLE);
	}

	public String getCtrlKey() {
		return _ctrlKey;
	}

	public void setCtrlKey(String ctrlKey) {
		this._ctrlKey = ctrlKey;
		if (ctrlKey != null && ctrlKey.length() == 0)
			ctrlKey = null;
		if (!Objects.equals(ctrlKey, _ctrlKey)) {
			this._ctrlKey = ctrlKey;
			smartUpdate("ctrlKey", ctrlKey);
		}
	}

	public boolean isFilterMode() {
		return _filterMode;
	}

	public void setFilterMode(boolean filterMode) {
		if (this._filterMode != filterMode) {
			this._filterMode = filterMode;
			smartUpdate("filterMode", filterMode);
		}
	}

	public int getMinWidth() {
		return _minWidth;
	}

	public void setMinWidth(int minWidth) {
		if (minWidth != _minWidth) {
			this._minWidth = minWidth;
			smartUpdate("minWidth", minWidth);
		}
	}

	public int getMinHeight() {
		return _minHeight;
	}

	public void setMinHeight(int minHeight) {
		if (minHeight != _minHeight) {
			this._minHeight = minHeight;
			smartUpdate("minHeight", minHeight);
		}
	}

	public String getNoDisableItems() {
		return _noDisableItems;
	}

	public void setNoDisableItems(String noDisableItems) {
		if (noDisableItems != null && noDisableItems.length() == 0)
			noDisableItems = null;
		if (!Objects.equals(noDisableItems, _noDisableItems)) {
			this._noDisableItems = noDisableItems;
			smartUpdate("noDisableItems", noDisableItems);
		}
	}

	public String getItems() {
		return _items;
	}

	public void setItems(String items) {
		if (items != null && items.length() == 0)
			items = null;
		if (!Objects.equals(items, _items)) {
			this._items = items;
			smartUpdate("items", items);
		}
	}

	public boolean isWellFormatMode() {
		return _wellFormatMode;
	}

	public void setWellFormatMode(boolean wellFormatMode) {
		if (this._wellFormatMode != wellFormatMode) {
			this._wellFormatMode = wellFormatMode;
			smartUpdate("wellFormatMode", wellFormatMode);
		}

	}

	public int getResizeType() {
		return _resizeType;
	}

	public void setResizeType(int resizeType) {
		if (this._resizeType != resizeType) {
			this._resizeType = resizeType;
			smartUpdate("resizeType", resizeType);
		}
	}

	public String getLangType() {
		return _langType;
	}

	public void setLangType(String langType) {
		if (langType != null && langType.length() == 0)
			langType = null;
		if (!Objects.equals(langType, _langType)) {
			this._langType = langType;
			smartUpdate("langType", langType);
		}
	}

	public String getUrlType() {
		return _urlType;
	}

	public void setUrlType(String urlType) {
		if (urlType != null && urlType.length() == 0)
			urlType = null;
		if (!Objects.equals(urlType, _urlType)) {
			this._urlType = urlType;
			smartUpdate("urlType", urlType);
		}
	}

	public boolean isDesignMode() {
		return _designMode;
	}

	public void setDesignMode(boolean designMode) {
		if (this._designMode != designMode) {
			this._designMode = designMode;
			smartUpdate("designMode", designMode);
		}
	}

	public boolean isFullscreenMode() {
		return _fullscreenMode;
	}

	public void setFullscreenMode(boolean fullscreenMode) {
		if (this._fullscreenMode != fullscreenMode) {
			this._fullscreenMode = fullscreenMode;
			smartUpdate("fullscreenMode", fullscreenMode);
		}
	}

	public String getNewlineTag() {
		return _newlineTag;
	}

	public void setNewlineTag(String newlineTag) {
		if (newlineTag != null && newlineTag.length() == 0)
			newlineTag = null;
		if (!Objects.equals(newlineTag, _newlineTag)) {
			this._newlineTag = newlineTag;
			smartUpdate("urlType", newlineTag);
		}
	}

	public boolean isUseContextmenu() {
		return _useContextmenu;
	}

	public void setUseContextmenu(boolean useContextmenu) {
		if (this._useContextmenu != useContextmenu) {
			this._useContextmenu = useContextmenu;
			smartUpdate("useContextmenu", useContextmenu);
		}
	}

	public boolean isAllowPreviewEmoticons() {
		return _allowPreviewEmoticons;
	}

	public void setAllowPreviewEmoticons(boolean allowPreviewEmoticons) {
		if (this._allowPreviewEmoticons != allowPreviewEmoticons) {
			this._allowPreviewEmoticons = allowPreviewEmoticons;
			smartUpdate("allowPreviewEmoticons", allowPreviewEmoticons);
		}
	}

	public boolean isAllowImageUpload() {
		return _allowImageUpload;
	}

	public void setAllowImageUpload(boolean allowImageUpload) {
		if (this._allowImageUpload != allowImageUpload) {
			this._allowImageUpload = allowImageUpload;
			smartUpdate("allowImageUpload", allowImageUpload);
		}
	}

	public boolean isAllowFlashUpload() {
		return _allowFlashUpload;
	}

	public void setAllowFlashUpload(boolean allowFlashUpload) {
		if (this._allowFlashUpload != allowFlashUpload) {
			this._allowFlashUpload = allowFlashUpload;
			smartUpdate("allowFlashUpload", allowFlashUpload);
		}
	}

	public boolean isAllowMediaUpload() {
		return _allowMediaUpload;
	}

	public void setAllowMediaUpload(boolean allowMediaUpload) {
		if (this._allowMediaUpload != allowMediaUpload) {
			this._allowMediaUpload = allowMediaUpload;
			smartUpdate("allowMediaUpload", allowMediaUpload);
		}
	}

	public boolean isAllowFileUpload() {
		return _allowFileUpload;
	}

	public void setAllowFileUpload(boolean allowFileUpload) {
		if (this._allowFileUpload != allowFileUpload) {
			this._allowFileUpload = allowFileUpload;
			smartUpdate("allowFileUpload", allowFileUpload);
		}
	}

	public boolean isAllowFileManager() {
		return _allowFileManager;
	}

	public void setAllowFileManager(boolean allowFileManager) {
		if (this._allowFileManager != allowFileManager) {
			this._allowFileManager = allowFileManager;
			smartUpdate("allowFileManager", allowFileManager);
		}
	}

	public boolean isFullscreenShortcut() {
		return _fullscreenShortcut;
	}

	public void setFullscreenShortcut(boolean fullscreenShortcut) {
		if (this._fullscreenShortcut != fullscreenShortcut) {
			this._fullscreenShortcut = fullscreenShortcut;
			smartUpdate("fullscreenShortcut", fullscreenShortcut);
		}
	}

	public boolean isFillDescAfterUploadImage() {
		return _fillDescAfterUploadImage;
	}

	public void setFillDescAfterUploadImage(boolean fillDescAfterUploadImage) {
		if (this._fillDescAfterUploadImage != fillDescAfterUploadImage) {
			this._fillDescAfterUploadImage = fillDescAfterUploadImage;
			smartUpdate("fillDescAfterUploadImage", fillDescAfterUploadImage);
		}
	}

	public boolean isAllowImageRemote() {
		return _allowImageRemote;
	}

	public void setAllowImageRemote(boolean allowImageRemote) {
		if (this._allowImageRemote != allowImageRemote) {
			this._allowImageRemote = allowImageRemote;
			smartUpdate("allowImageRemote", allowImageRemote);
		}
	}

	@Override
	public boolean isDisabled() {
		return _disabled;
	}

	@Override
	public void setDisabled(boolean disabled) {
		if (this._disabled != disabled) {
			this._disabled = disabled;
			smartUpdate("disabled", _disabled);
		}
	}

	@Override
	public boolean isReadonly() {
		return isDisabled();
	}

	@Override
	public void setReadonly(boolean readonly) {
		setDisabled(readonly);
	}

	/**
	 * @return the skin
	 */
	public String getSkin() {
		return _skin;
	}

	/**
	 * @param skin
	 *            the skin to set
	 */
	public void setSkin(String skin) {
		if (skin != null && skin.length() == 0)
			skin = null;
		if (!Objects.equals(this._skin, skin)) {
			_skin = skin;
			smartUpdate("skin", _skin);
		}
	}

	/**
	 * Returns the value in this CKeditor.
	 */
	public String getValue() {
		return _value;
	}

	/**
	 * Sets the value for this CKeditor.
	 */
	public void setValue(Object value) {
		if (value == null)
			value = "";
		if (!value.equals(_value)) {
			_value = (String) value;
			if (_txtByClient == null || !Objects.equals(_txtByClient, value)) {
				_txtByClient = null;
				smartUpdate("value", value);
			}
		}
	}

	/**
	 * Returns the toolbar set of this CKeditor.
	 * <p>
	 * Default: null
	 */
	public String getToolbar() {
		return _toolbar;
	}

	/**
	 * 
	 */
	public void focus() {
		response(new AuFocus(this));
	}

	/**
	 * @param focus
	 */
	public void setFocus(boolean focus) {
		if (focus)
			focus();
	}

	/**
	 * Sets the toolbar set for this CKeditor.
	 */
	public void setToolbar(String toolbar) {
		if (toolbar != null && toolbar.length() == 0)
			toolbar = null;
		if (!Objects.equals(toolbar, _toolbar)) {
			_toolbar = toolbar;
			smartUpdate("toolbar", toolbar);
		}
	}

	/**
	 * Returns the width of this CKeditor.
	 * <p>
	 * Default: 100%
	 */
	public String getWidth() {
		return _width;
	}

	/**
	 * Sets the width of this CKeditor.
	 */
	public void setWidth(String width) {
		if (width != null && width.length() == 0)
			width = null;
		if (!Objects.equals(width, _width)) {
			_width = width;
			smartUpdate("width", width);
		}
	}

	/**
	 * Returns the height of this CKeditor.
	 * <p>
	 * Default: 200px
	 */
	public String getHeight() {
		return _height;
	}

	/**
	 * Sets the height of this CKeditor.
	 */
	public void setHeight(String height) {
		if (height != null && height.length() == 0)
			height = null;
		if (!Objects.equals(height, _height)) {
			_height = height;
			smartUpdate("height", height);
		}
	}

	/**
	 * Sets vertical flexibility hint of this component.
	 * <p>
	 * Number flex indicates how this component's container distributes
	 * remaining empty space among its children vertically. Flexible component
	 * grow and shrink to fit their given space. Flexible components with larger
	 * flex values will be made larger than components with lower flex values,
	 * at the ratio determined by all flexible components. The actual flex value
	 * is not relevant unless there are other flexible components within the
	 * same container. Once the default sizes of components in a container are
	 * calculated, the remaining space in the container is divided among the
	 * flexible components, according to their flex ratios.
	 * </p>
	 * <p>
	 * Only positive integer allowed for ckeditor hflex value, other value make
	 * no effect of it.
	 * </p>
	 * 
	 * @param flex
	 *            the vertical flex hint.
	 * @since 3.6.0
	 * @see #setHflex
	 * @see #getVflex
	 */
	public void setVflex(String flex) {
		if (flex != null && flex.length() == 0)
			flex = null;
		if (!Objects.equals(_vflex, flex)) {
			_vflex = flex;
			smartUpdate("vflex", flex);
		}
	}

	/**
	 * Return vertical flex hint of this component.
	 * <p>
	 * Default: null
	 * 
	 * @return vertical flex hint of this component.
	 * @since 3.6.0
	 * @see #setVflex
	 */
	public String getVflex() {
		return _vflex;
	}

	/**
	 * Sets horizontal flex hint of this component.
	 * <p>
	 * Number flex indicates how this component's container distributes
	 * remaining empty space among its children horizontally. Flexible component
	 * grow and shrink to fit their given space. Flexible components with larger
	 * flex values will be made larger than components with lower flex values,
	 * at the ratio determined by all flexible components. The actual flex value
	 * is not relevant unless there are other flexible components within the
	 * same container. Once the default sizes of components in a container are
	 * calculated, the remaining space in the container is divided among the
	 * flexible components, according to their flex ratios.
	 * </p>
	 * <p>
	 * Only positive integer allowed for ckeditor vflex value, other value make
	 * no effect of it.
	 * </p>
	 * 
	 * @param flex
	 *            horizontal flex hint of this component.
	 * @since 3.6.0
	 * @see #setVflex
	 * @see #getHflex
	 */
	public void setHflex(String flex) {
		if (flex != null && flex.length() == 0)
			flex = null;
		if (!Objects.equals(_hflex, flex)) {
			_hflex = flex;
			smartUpdate("hflex", flex);
		}
	}

	/**
	 * Returns horizontal flex hint of this component.
	 * <p>
	 * Default: null
	 * 
	 * @return horizontal flex hint of this component.
	 * @since 3.6.0
	 * @see #setHflex
	 */
	public String getHflex() {
		return _hflex;
	}

	/**
	 * Returns whether enable to automatically grow the height of the component
	 * or not.
	 * <p>
	 * Default: false.
	 */
	public boolean isAutoHeight() {
		return _autoHeight;
	}

	/**
	 * Sets whether enable to automatically grow the height of the component or
	 * not.
	 * 
	 * @param autoHeight
	 */
	public void setAutoHeight(boolean autoHeight) {
		if (_autoHeight != autoHeight) {
			_autoHeight = autoHeight;
			smartUpdate("autoHeight", _autoHeight);
		}
	};

	public void service(org.zkoss.zk.au.AuRequest request, boolean everError) {
		final String cmd = request.getCommand();
		if (cmd.equals(Events.ON_CHANGE) || cmd.equals(Events.ON_CTRL_KEY)) {
			InputEvent evt = InputEvent.getInputEvent(request, _value);
			final String value = evt.getValue();
			_txtByClient = value;
			try {
				final Object oldval = _value;
				setValue(value);
				if (oldval == _value && cmd.equals(Events.ON_CHANGE))
					return;
			} finally {
				_txtByClient = null;
			}
			Events.postEvent(evt);
		} else if (cmd.equals(Events.ON_CHANGING)) {
			Events.postEvent(InputEvent.getInputEvent(request, _value));
		} else
			super.service(request, everError);
	}

	protected void renderProperties(org.zkoss.zk.ui.sys.ContentRenderer renderer)
			throws java.io.IOException {
		super.renderProperties(renderer);
		render(renderer, "value", _value);
		if (!Strings.isBlank(_width))
			render(renderer, "width", _width);
		if (!Strings.isBlank(_height))
			render(renderer, "height", _height);
		if (!Strings.isBlank(_toolbar))
			render(renderer, "toolbar", _toolbar);
		if (!Strings.isBlank(_skin))
			render(renderer, "skin", _skin);
		if (!Strings.isBlank(_hflex))
			render(renderer, "hflex", _hflex);
		if (!Strings.isBlank(_vflex))
			render(renderer, "vflex", _vflex);
		if (_minWidth > 0)
			render(renderer, "minWidth", this._minWidth);
		if (_minHeight > 0)
			render(renderer, "minHeight", this._minHeight);
		if (!Strings.isBlank(_noDisableItems))
			render(renderer, "noDisableItems", this._noDisableItems);
		if (!Strings.isBlank(_items))
			render(renderer, "items", this._items);
		if (!Strings.isBlank(_langType))
			render(renderer, "langType", this._langType);
		if (!Strings.isBlank(_urlType))
			render(renderer, "urlType", this._urlType);
		if (!Strings.isBlank(_newlineTag))
			render(renderer, "newlineTag", this._newlineTag);
		if (!Strings.isBlank(_ctrlKey))
			render(renderer, "ctrlKey", _ctrlKey);

		render(renderer, "autoHeight", _autoHeight);
		render(renderer, "disabled", _disabled);
		render(renderer, "disabled", _disabled);
		render(renderer, "filterMode", _filterMode);
		render(renderer, "wellFormatMode", _wellFormatMode);
		render(renderer, "designMode", _designMode);
		render(renderer, "fullscreenMode", _fullscreenMode);
		render(renderer, "useContextmenu", _useContextmenu);
		render(renderer, "allowPreviewEmoticons", _allowPreviewEmoticons);
		render(renderer, "allowImageUpload", _allowImageUpload);
		render(renderer, "allowFlashUpload", _allowFlashUpload);
		render(renderer, "allowMediaUpload", _allowMediaUpload);
		render(renderer, "allowFileUpload", _allowFileUpload);
		render(renderer, "allowFileManager", _allowFileManager);
		render(renderer, "fullscreenShortcut", _fullscreenShortcut);
		render(renderer, "fillDescAfterUploadImage", _fillDescAfterUploadImage);
		render(renderer, "allowImageRemote", _allowImageRemote);
		render(renderer, "resizeType", _resizeType);
	}

	public boolean isChildable() {
		return false;
	}

}
